package com.googlecode.mcwalle;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.danga.MemCached.Logger;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
import com.googlecode.mcwalle.response.ItemInfo;
import com.googlecode.mcwalle.response.StatsCachedumpResponse;
import com.googlecode.mcwalle.response.StatsSlabsResponse;

/**
 * @author Li Weibo (weibo.leo@gmail.com) //I believe spring-brother
 * @since 2011-10-26 下午05:53:59
 */
public class McWalle {

	protected Log logger = LogFactory.getLog(this.getClass());
	
	public void gc(String host, int port) {
		
		McClientImpl statsClient = new McClientImpl(host, port);
		statsClient.init();
		McClientImpl deleteClient = new McClientImpl(host, port);
		deleteClient.init();
		
		
		StatsSlabsResponse res = statsClient.statsSlabs();
		Iterator<Integer> iter = res.slabNumberIterator();
		
		long totalReleasedBytes = 0;
		long totalReleasedItems = 0;
		
		while (iter.hasNext()) {
			int slabNumber = iter.next();
			StatsCachedumpResponse cacheDumpRes = statsClient.statsCacheDump(slabNumber, 0);
			for (ItemInfo info : cacheDumpRes) {
				if (info.isExpired()) {
					boolean deleted = deleteClient.delete(info.getKey());
					if (deleted) {	//对过期数据的删除操作应该直接return false，如果为true，可能是哪里出了问题
						throw new RuntimeException("delected return true on item: " + info);
					}
					System.out.println(info);
					totalReleasedBytes += info.getBytes();
					totalReleasedItems ++;
				}
			}
			break;	//TODO 这里为了测试才break的，正式版本应该去掉break
		}
		System.out.println("done");
		System.out.println(totalReleasedBytes + " bytes released");
		System.out.println(totalReleasedItems + " items released");
		
		statsClient.destroy();
		deleteClient.destroy();
	}
	
	/*public void gc(String server) {
		
		MemCachedClient client = initClient(server);
		Map<String, Map<String, String>> ret = client.statsCacheDump(8, 10000);
		int expireCount = 0;
		for(Entry<String, Map<String, String>> serverEntry : ret.entrySet()) {
			System.out.println(serverEntry.getKey());
			for (Entry<String, String> kvEntry : serverEntry.getValue().entrySet()) {
				String itemKey = kvEntry.getKey().trim();
				String itemInfo = kvEntry.getValue().trim();
				String[] ss = itemInfo.substring(1, itemInfo.length() - 1).split(";");
				int bytes = Integer.parseInt(ss[0].trim().split(" ")[0]);
				int expireTime = Integer.parseInt(ss[1].trim().split(" ")[0]);
				
				
				
				if (1000l * expireTime < System.currentTimeMillis()) {
					System.out.println(itemKey + ": " + bytes + "bytes, " + new Date(1000l * expireTime));
					expireCount ++;
					if (!client.delete(itemKey)) {
						System.out.println(itemKey + "Not expiress");
					}
				}
				
				
			}
		}
		
		System.out.println(expireCount + " expires");
	}*/
	
	private MemCachedClient initClient(String server) {

        int initialConnections = 10;
        int minSpareConnections = 5;
        int maxSpareConnections = 100;
        long maxIdleTime = 1000 * 60 * 30; // 30 minutes
        long maxBusyTime = 1000 * 60 * 5; // 5 minutes
        long maintThreadSleep = 1000 * 5; // 5 seconds
        int socketTimeOut = 100; //milliseconds to block on reads
        int socketConnectTO = 1000 * 1; //milliseconds to block on initial connections.  If 0, then will use blocking connect (default)

        //get a new SockIOPool
        SockIOPool sockPool = SockIOPool.getInstance(server);

        sockPool.setServers(new String[]{server});
        sockPool.setInitConn(initialConnections);
        sockPool.setMinConn(minSpareConnections);
        sockPool.setMaxConn(maxSpareConnections);
        sockPool.setMaxIdle(maxIdleTime);
        sockPool.setMaxBusyTime(maxBusyTime);
        sockPool.setMaintSleep(maintThreadSleep);
        sockPool.setSocketTO(socketTimeOut);
        sockPool.setSocketConnectTO(socketConnectTO);
        sockPool.setNagle(false); // turn off Nagle's algorithm on all sockets in pool	
        sockPool.setHashingAlg(SockIOPool.CONSISTENT_HASH);
        sockPool.setAliveCheck(false); // disable health check of socket on checkout
        sockPool.initialize();
        
        MemCachedClient client = new MemCachedClient(server, false);
        client.setSanitizeKeys(false); //不对key进行编码
        
        MemCachedClient.log.setLevel(Logger.LEVEL_ERROR);	//log级别设置为warn
        return client;
    }
	
	public static void main(String[] args) {
		McWalle walle = new McWalle();
		walle.gc("10.3.22.59", 11211);
	}
	
}
